home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / daemons / ipServer / tcpOutput.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-09-27  |  19.7 KB  |  679 lines

  1. /* 
  2.  * tcpOutput.c --
  3.  *
  4.  *    Routines to handle TCP output processing.
  5.  *
  6.  *    Based on 4.3BSD    @(#)tcp_output.c    7.12 (Berkeley) 3/24/88
  7.  *
  8.  *    To do:
  9.  *    1) allow user-supplied TCP options to be sent with the segment.
  10.  *
  11.  *
  12.  *
  13.  * Copyright 1987 Regents of the University of California
  14.  * All rights reserved.
  15.  * Permission to use, copy, modify, and distribute this
  16.  * software and its documentation for any purpose and without
  17.  * fee is hereby granted, provided that the above copyright
  18.  * notice appear in all copies.  The University of California
  19.  * makes no representations about the suitability of this
  20.  * software for any purpose.  It is provided "as is" without
  21.  * express or implied warranty.
  22.  */
  23.  
  24. #ifndef lint
  25. static char rcsid[] = "$Header: /sprite/src/daemons/ipServer/RCS/tcpOutput.c,v 1.8 90/02/22 14:22:04 ouster Exp $ SPRITE (Berkeley)";
  26. #endif not lint
  27.  
  28.  
  29. #include "sprite.h"
  30. #include "ipServer.h"
  31. #include "stat.h"
  32. #include "ip.h"
  33. #include "tcp.h"
  34. #include "tcpInt.h"
  35. #include "netInet.h"
  36.  
  37. /*
  38.  * Initial TCP options.
  39.  */
  40. struct {
  41.     char    kind;
  42.     char    length;
  43.     unsigned short value;
  44. } initialOptions = { 
  45.     NET_TCP_OPTION_MAX_SEG_SIZE, 
  46.     sizeof(initialOptions), 
  47.     0
  48. };
  49.  
  50. /*
  51.  * Values for the TCP header flags when in a certain state.
  52.  */
  53. static int stateToOutputFlags[] = {
  54.    NET_TCP_RST_FLAG|NET_TCP_ACK_FLAG,     /* CLOSED */
  55.    0,                     /* LISTEN */
  56.    NET_TCP_SYN_FLAG,             /* SYN_SENT */
  57.    NET_TCP_SYN_FLAG|NET_TCP_ACK_FLAG,    /* SYN_RECEIVED */
  58.    NET_TCP_ACK_FLAG,             /* ESTABLISHED */
  59.  
  60.    NET_TCP_ACK_FLAG,            /* CLOSE_WAIT */
  61.    NET_TCP_FIN_FLAG|NET_TCP_ACK_FLAG,     /* LAST_ACK */
  62.  
  63.    NET_TCP_FIN_FLAG|NET_TCP_ACK_FLAG,     /* FIN_WAIT_1 */
  64.    NET_TCP_ACK_FLAG,            /* FIN_WAIT_2 */
  65.    NET_TCP_FIN_FLAG|NET_TCP_ACK_FLAG,     /* CLOSING */
  66.    NET_TCP_ACK_FLAG,            /* TIME_WAIT */
  67. }; 
  68.  
  69. static int     timeToLive = NET_TCP_TTL;
  70. static void    CalcChecksum();
  71.  
  72.  
  73. /*
  74.  *----------------------------------------------------------------------
  75.  *
  76.  * TCPOutput --
  77.  *
  78.  *    This routine determines what data needs to be sent to the
  79.  *    remote peer.
  80.  *
  81.  * Results:
  82.  *    SUCCESS        - currently always returned.
  83.  *
  84.  * Side effects:
  85.  *    One or more packets may be sent to the network.
  86.  *
  87.  *----------------------------------------------------------------------
  88.  */
  89.  
  90. ReturnStatus
  91. TCPOutput(sockPtr, tcbPtr)
  92.     Sock_InfoPtr        sockPtr;
  93.     register TCPControlBlock    *tcbPtr;
  94. {
  95.     register int    len;
  96.     register int    window;
  97.     int            amtUnacked;
  98.     int            sendBufAmtUsed;
  99.     int            flags;
  100.     Boolean        idle;
  101.     Boolean        sendAlot;
  102.     unsigned char    *opt;
  103.     int            optlen = 0;
  104.     IPS_Packet        packet;
  105.     Address        ptr;
  106.  
  107.     /*
  108.      * Determine length of data that should be transmitted, and flags that
  109.      * will be used.  If there is some data or critical controls (SYN, RST)
  110.      * to send, then transmit; otherwise, investigate further.
  111.      *
  112.      * We're idle if all the stuff we've sent has been ACKed.
  113.      */
  114.  
  115.     idle = (tcbPtr->send.maxSent == tcbPtr->send.unAck);
  116.  
  117. again:
  118.  
  119.     sendAlot = FALSE;
  120.     amtUnacked = tcbPtr->send.next - tcbPtr->send.unAck;
  121.     window = MIN(tcbPtr->send.window, tcbPtr->send.congWindow);
  122.  
  123.     /*
  124.      * If called from the persist timeout handler with a window of 0, 
  125.      * send 1 byte.  Otherwise, if the window is small but nonzero and 
  126.      * the timer has expired, we will send what we can and go to the 
  127.      * transmit state.
  128.      */
  129.  
  130.     if (tcbPtr->force) {
  131.     if (window == 0) {
  132.         window = 1;
  133.     } else {
  134.         tcbPtr->timer[TCP_TIMER_PERSIST] = 0;
  135.         tcbPtr->rxtshift = 0;
  136.     }
  137.     }
  138.  
  139.     sendBufAmtUsed = Sock_BufSize(sockPtr, SOCK_SEND_BUF, SOCK_BUF_USED);
  140.  
  141.     len = MIN(sendBufAmtUsed, window) - amtUnacked;
  142.  
  143.     flags = stateToOutputFlags[(int)tcbPtr->state];
  144.     if (len < 0) {
  145.     /*
  146.      * If a FIN has been sent but not acked, and we haven't been
  147.      * called to retransmit, then len will be -1 so transmit if
  148.      * acking, otherwise return.  If a FIN has not been sent, the
  149.      * window shrank after we sent into it.  If the window shrank to
  150.      * 0, cancel the pending retransmit and pull send.next back to
  151.      * (closed) window.  We will enter the persist state below.  If
  152.      * the window didn't close completely, just wait for an ACK.
  153.      */
  154.  
  155.     len = 0;
  156.     if (window == 0) {
  157.         tcbPtr->timer[TCP_TIMER_REXMT] = 0;
  158.         tcbPtr->send.next = tcbPtr->send.unAck;
  159.     }
  160.     } 
  161.     if (len > tcbPtr->maxSegSize) {
  162.     len = tcbPtr->maxSegSize;
  163.     sendAlot = TRUE;
  164.     }
  165.  
  166.     /*
  167.      * If there's data to be sent, make sure the FIN flag is off.
  168.      */
  169.     if (TCP_SEQ_LT(tcbPtr->send.next+ len, tcbPtr->send.unAck+ sendBufAmtUsed)){
  170.     flags &= ~NET_TCP_FIN_FLAG;
  171.     }
  172.     window = Sock_BufSize(sockPtr, SOCK_RECV_BUF, SOCK_BUF_FREE); 
  173.  
  174.  
  175.     /*
  176.      * If our state indicates that FIN should be sent and we have not 
  177.      * yet done so, or we're retransmitting the FIN, then we need to send.
  178.      */
  179.     if ((flags & NET_TCP_FIN_FLAG) &&
  180.       ( !(tcbPtr->flags & TCP_SENT_FIN) || 
  181.       (tcbPtr->send.next == tcbPtr->send.unAck))) {
  182.     goto send;
  183.     }
  184.  
  185.     /*
  186.      * We want to send a packet if any of the following conditions hold:
  187.      *  1) we owe our peer an ACK.
  188.      *  2) we need to send a SYN or RESET flag
  189.      *  3) there's urgent data to send.
  190.      */
  191.     if ((tcbPtr->flags & TCP_ACK_NOW) ||
  192.     (flags & (NET_TCP_SYN_FLAG|NET_TCP_RST_FLAG)) ||
  193.     (TCP_SEQ_GT(tcbPtr->send.urgentPtr, tcbPtr->send.unAck))) {
  194.     goto send;
  195.     }
  196.  
  197.     /*
  198.      * Sender silly window avoidance.  If the connection is idle and we
  199.      * can send all data, either a maximum segment or at least a maximum
  200.      * default-size segment, then do it. Also send if the persist force flag 
  201.      * is set. If peer's buffer is tiny, then send when window is at least 
  202.      * half open.  If retransmitting (possibly after persist timer forced us 
  203.      * to send into a small window), then we must resend.
  204.      */
  205.     if (len != 0) {
  206.     if (len == tcbPtr->maxSegSize) {
  207.         goto send;
  208.     }
  209.     if ((idle || (tcbPtr->flags & TCP_NO_DELAY)) &&
  210.         (len + amtUnacked) >= sendBufAmtUsed) {
  211.         goto send;
  212.     }
  213.     if (tcbPtr->force ||
  214.         (len >= (tcbPtr->send.maxWindow / 2)) ||
  215.         (TCP_SEQ_LT(tcbPtr->send.next, tcbPtr->send.maxSent))) {
  216.         goto send;
  217.     }
  218.     }
  219.  
  220.     /*
  221.      * Compare the available window to amount of window known to the peer
  222.      * (i.e., advertised window less next expected input.)  If the difference
  223.      * is 35% or more of the maximum possible window, then we want to send
  224.      * a window update to the peer.
  225.      */
  226.     if (window > 0) {
  227.     int advertised = window - (tcbPtr->recv.advtWindow - tcbPtr->recv.next);
  228.     if (Sock_BufSize(sockPtr, SOCK_RECV_BUF, SOCK_BUF_USED) == 0 &&
  229.         advertised >= (2 * tcbPtr->maxSegSize)) {
  230.         goto send;
  231.     }
  232.     if (((100 * advertised) / 
  233.         Sock_BufSize(sockPtr, SOCK_RECV_BUF, SOCK_BUF_MAX_SIZE)) >= 35){
  234.         goto send;
  235.     }
  236.     }
  237.  
  238.     /*
  239.      * TCP window updates are not reliable, so a polling protocol
  240.      * using "persist" packets is used to insure receipt of window
  241.      * updates.  The three "states" for the output side are:
  242.      *      idle            not doing retransmits or persists,
  243.      *      persisting        to move a small or zero window,
  244.      *      (re)transmitting    and thereby not persisting.
  245.      *
  246.      * tcbPtr->timer[TCP_TIMER_PERSIST] is set when we are in persist state.
  247.      * tcbPtr->force  is set when we are called to send a persist packet.
  248.      * tcbPtr->timer[TCP_TIMER_REXMT]  is set when we are retransmitting
  249.      * The output side is idle when both timers are zero.
  250.      *
  251.      * If the send window is too small, and there are data to transmit, and no
  252.      * retransmit or persist timer is pending, then go to the persist state.
  253.      * If nothing happens soon, send when the timer expires:  if the window is
  254.      * nonzero, transmit what we can, otherwise force out a byte.
  255.      */
  256.  
  257.     if (sendBufAmtUsed != 0 &&
  258.     (tcbPtr->timer[TCP_TIMER_REXMT] == 0) &&
  259.     (tcbPtr->timer[TCP_TIMER_PERSIST] == 0)) {
  260.  
  261.     tcbPtr->rxtshift = 0;
  262.     TCPSetPersist(tcbPtr);
  263.     }
  264.  
  265.     /*
  266.      * No reason to send a segment, just return.
  267.      */
  268.     return(SUCCESS);
  269.  
  270. send:
  271.  
  272.     /*
  273.      * Initialize a packet and copy the data to be transmitted into the
  274.      * packet. Also, initialize the header from the template for sends 
  275.      * on this connection.
  276.      */
  277.  
  278.     IPS_InitPacket(len, &packet);
  279.  
  280.     if (len != 0) {
  281.     if (tcbPtr->force && len == 1) {
  282.         stats.tcp.send.probe++;
  283.     } else if (TCP_SEQ_LT(tcbPtr->send.next, tcbPtr->send.maxSent)) {
  284.         stats.tcp.send.rexmitPack++;
  285.         stats.tcp.send.rexmitByte += len;
  286.     } else {
  287.         stats.tcp.send.pack++;
  288.         stats.tcp.send.byte += len;
  289.     }
  290.     Sock_BufCopy(sockPtr, SOCK_SEND_BUF, amtUnacked, len, packet.data);
  291.     if (ips_Debug) {
  292.         (void) fprintf(stderr, "TCP Output: sending '%.*s'\n",
  293.         MIN(len, 20), packet.data);
  294.     }
  295.     } else if (tcbPtr->flags & TCP_ACK_NOW) {
  296.     stats.tcp.send.acks++;
  297.     } else if (flags & (NET_TCP_SYN_FLAG|NET_TCP_FIN_FLAG|NET_TCP_RST_FLAG)) {
  298.     stats.tcp.send.ctrl++;
  299.     } else if (TCP_SEQ_GT(tcbPtr->send.urgentPtr, tcbPtr->send.unAck)) {
  300.     stats.tcp.send.urg++;
  301.     } else {
  302.     stats.tcp.send.winUpdate++;
  303.     }
  304.  
  305.  
  306.     /*
  307.      * Before the ESTABLISHED state, we must send the initial options
  308.      * unless an option is set to not do any options.
  309.      */
  310.     opt = (unsigned char *) NULL;
  311.     if (TCP_UNSYNCHRONIZED(tcbPtr->state) &&
  312.     !(tcbPtr->flags & TCP_IGNORE_OPTS)) {
  313.     unsigned short mss;
  314.  
  315.     mss = MIN(Sock_BufSize(sockPtr, SOCK_RECV_BUF, SOCK_BUF_MAX_SIZE) / 2,
  316.              TCPCalcMaxSegSize(tcbPtr));
  317.     if (mss > NET_IP_MAX_SEG_SIZE - sizeof(Net_TCPHeader)) {
  318.         opt = (unsigned char *) &initialOptions;
  319.         optlen = sizeof(initialOptions);
  320.         initialOptions.value = Net_HostToNetShort(mss);
  321.     }
  322. #ifdef not_def
  323.     } else if (tcbPtr->tcpOptions != (Address) NULL) {
  324.     opt = (unsigned char *) tcbPtr->tcpOptions;
  325.     optlen = tcbPtr->tcpOptLen;
  326. #endif not_def
  327.     }
  328.  
  329.     /*
  330.      * Copy the options to the packet. Make sure they are padded to
  331.      * an 4-byte multiple.
  332.      */
  333.     ptr = packet.data;
  334.     if (opt != (unsigned char *) NULL) {
  335.     int padLen = 0;
  336.     while ((optlen & 0x3) != 0) {
  337.         ptr--;
  338.         *ptr = NET_TCP_OPTION_EOL;
  339.         padLen++;
  340.     }
  341.     ptr -= optlen;
  342.     bcopy((Address)opt, ptr, (int)optlen);
  343.     optlen += padLen;
  344.     }
  345.  
  346. #define tcpHdrPtr    packet.hdr.tcpPtr
  347. #define ipHdrPtr    packet.ipPtr
  348.  
  349.     tcpHdrPtr = (Net_TCPHeader *) (ptr - sizeof(Net_TCPHeader));
  350.     packet.hdrLen = sizeof(Net_TCPHeader) + optlen;
  351.     ipHdrPtr = (Net_IPHeader *)(((Address) tcpHdrPtr) - sizeof(Net_IPHeader));
  352.  
  353.     if (tcbPtr->templatePtr == (Net_TCPHeader *)NULL) {
  354.     panic("TCPOutput: no template");
  355.     }
  356.     *tcpHdrPtr = *tcbPtr->templatePtr;
  357.  
  358.  
  359.     /*
  360.      * Fill in the header fields, remembering the maximum advertised
  361.      * window for use in delaying messages about window sizes.
  362.      * If resending a FIN, be sure not to use a new sequence number.
  363.      */
  364.     if ((flags & NET_TCP_FIN_FLAG) && 
  365.     (tcbPtr->flags & TCP_SENT_FIN) && 
  366.     len == 0) {
  367.  
  368.     tcbPtr->send.next--;
  369.     }
  370.     tcpHdrPtr->seqNum = Net_HostToNetInt(tcbPtr->send.next);
  371.     tcpHdrPtr->ackNum = Net_HostToNetInt(tcbPtr->recv.next);
  372.     tcpHdrPtr->dataOffset = (sizeof(Net_TCPHeader) + optlen) >> 2;
  373.     tcpHdrPtr->flags = flags;
  374.  
  375.     /*
  376.      * Calculate the receive window size.  Don't shrink the window, but 
  377.      * avoid silly window syndrome.
  378.      */
  379.  
  380.     if (window < Sock_BufSize(sockPtr,SOCK_RECV_BUF, SOCK_BUF_MAX_SIZE) / 4  &&
  381.     window < tcbPtr->maxSegSize) {
  382.     window = 0;
  383.     }
  384.     if (window > NET_IP_MAX_PACKET_SIZE) {
  385.     window = NET_IP_MAX_PACKET_SIZE;
  386.     }
  387.     if (window < (tcbPtr->recv.advtWindow - tcbPtr->recv.next)) {
  388.     window = tcbPtr->recv.advtWindow - tcbPtr->recv.next;
  389.     }
  390.     tcpHdrPtr->window = Net_HostToNetShort((unsigned short)window);
  391.  
  392.     if (TCP_SEQ_GT(tcbPtr->send.urgentPtr, tcbPtr->send.next)) {
  393.     tcpHdrPtr->urgentOffset = 
  394.         Net_HostToNetShort((unsigned short)(tcbPtr->send.urgentPtr - 
  395.             tcbPtr->send.next));
  396.     tcpHdrPtr->flags |= NET_TCP_URG_FLAG;
  397.     } else {
  398.     /*
  399.      * If there's no urgent pointer to send, then we pull
  400.      * the urgent pointer to the left edge of the send window
  401.      * so that it doesn't drift into the send window on sequence
  402.      * number wraparound.
  403.      */
  404.     tcbPtr->send.urgentPtr = tcbPtr->send.unAck; /* drag it along */
  405.     }
  406.  
  407.     /*
  408.      * If there's anything to send and we can send it all, set the PUSH flag.
  409.      * (This will keep happy those implementations which only give data
  410.      * to the user when a buffer fills or a PUSH comes in.)
  411.      */
  412.  
  413.     if ((len != 0) && 
  414.     ((amtUnacked+len) == Sock_BufSize(sockPtr, SOCK_SEND_BUF, 
  415.                 SOCK_BUF_USED) )) {
  416.     tcpHdrPtr->flags |= NET_TCP_PSH_FLAG;
  417.     }
  418.  
  419.     IP_FormatPacket(NET_IP_PROTOCOL_TCP,  timeToLive,
  420.             tcbPtr->IPTemplatePtr->source,
  421.             tcbPtr->IPTemplatePtr->dest, &packet);
  422.     CalcChecksum(&packet, len + optlen);
  423.  
  424.     /*
  425.      * When in the transmit state, time the transmission and arrange for
  426.      * the retransmit.  In the persist state, just set send.maxSent.
  427.      */
  428.     if ((!tcbPtr->force) || (tcbPtr->timer[TCP_TIMER_PERSIST] == 0)) {
  429.     TCPSeqNum    startSeq;
  430.  
  431.     startSeq = tcbPtr->send.next;
  432.     /*
  433.      * Advance send.next over sequence space of this segment.
  434.      */
  435.     if (flags & NET_TCP_SYN_FLAG) {
  436.         tcbPtr->send.next++;
  437.     }
  438.     if (flags & NET_TCP_FIN_FLAG) {
  439.         tcbPtr->send.next++;
  440.         tcbPtr->flags |= TCP_SENT_FIN;
  441.     }
  442.  
  443.     tcbPtr->send.next += len;
  444.     if (TCP_SEQ_GT(tcbPtr->send.next, tcbPtr->send.maxSent)) {
  445.         tcbPtr->send.maxSent = tcbPtr->send.next;
  446.  
  447.         /*
  448.          * Time this transmission if it's not a retransmission and
  449.          * we are not currently timing anything.
  450.          */
  451.         if (tcbPtr->rtt == 0) {
  452.         tcbPtr->rtt = 1;
  453.         tcbPtr->rtseq = startSeq;
  454.         stats.tcp.segsTimed++;
  455.         }
  456.     }
  457.  
  458.     /*
  459.      * Set the retransmit timer if it's not currently set
  460.      * and we're not doing an ACK or a keep-alive probe.
  461.      * The initial value for the retransmit timer is smoothed
  462.      * round-trip time + 2 * round-trip time variance.
  463.      * Also initialize the shift counter, which is used for backoff
  464.      * of retransmit time.
  465.      */
  466.     if (tcbPtr->timer[TCP_TIMER_REXMT] == 0 &&
  467.         tcbPtr->send.next != tcbPtr->send.unAck) {
  468.  
  469.         tcbPtr->timer[TCP_TIMER_REXMT] = tcbPtr->rxtcur;
  470.         if (tcbPtr->timer[TCP_TIMER_PERSIST] != 0) {
  471.         tcbPtr->timer[TCP_TIMER_PERSIST] = 0;
  472.         tcbPtr->rxtshift = 0;
  473.         }
  474.     }
  475.     } else {
  476.     if (TCP_SEQ_GT(tcbPtr->send.next + len, tcbPtr->send.maxSent)) {
  477.         tcbPtr->send.maxSent = tcbPtr->send.next + len;
  478.     }
  479.     }
  480.  
  481.     /*
  482.      * Trace this operation if debugging is set.
  483.      */
  484.  
  485.     if (Sock_IsOptionSet(sockPtr, NET_OPT_DEBUG)) {
  486.     TCPTrace(TCP_TRACE_OUTPUT, tcbPtr->state, tcbPtr, tcpHdrPtr, len);
  487.     }
  488.     if (ips_Debug) {
  489.     (void) fprintf(stderr, 
  490.             "TCP Output: %d bytes <%x,%d,#%d> -> <%x,%d>\n\t", 
  491.             len, 
  492.             Net_NetToHostInt(ipHdrPtr->source), 
  493.             Net_NetToHostShort(tcpHdrPtr->srcPort), 
  494.             Net_NetToHostShort(ipHdrPtr->ident),
  495.             Net_NetToHostInt(ipHdrPtr->dest), 
  496.             Net_NetToHostShort(tcpHdrPtr->destPort));
  497.     TCPPrintHdrFlags(stderr, tcpHdrPtr->flags);
  498.     (void) fprintf(stderr, "  seq=%d, ack=%d, wind=%d\n", 
  499.         Net_NetToHostInt(tcpHdrPtr->seqNum), 
  500.         Net_NetToHostInt(tcpHdrPtr->ackNum),
  501.         Net_NetToHostShort(tcpHdrPtr->window));
  502.     }
  503.  
  504.  
  505.     IP_QueueOutput(&packet);
  506. #ifdef old_way
  507.     {
  508.     ReturnStatus    status;
  509.     status = IP_Output(&packet, TRUE);
  510.     free(packet.base);
  511.     if (status != SUCCESS) {
  512.         return(status);
  513.     }
  514.     }
  515. #endif old_way
  516.  
  517.     stats.tcp.send.total++;
  518.  
  519.     /*
  520.      * The data have been sent (as far as we can tell). If this advertises a 
  521.      * larger window than any other segment, then remember the size of 
  522.      * the advertised window. Any pending ACK has now been sent.
  523.      */
  524.  
  525.     if ((window > 0) && 
  526.     TCP_SEQ_GT(tcbPtr->recv.next + window, tcbPtr->recv.advtWindow)) {
  527.     tcbPtr->recv.advtWindow = tcbPtr->recv.next + window;
  528.     }
  529.  
  530.     tcbPtr->flags &= ~(TCP_ACK_NOW | TCP_DELAY_ACK);
  531.  
  532.     if (sendAlot) {
  533.     goto again;
  534.     }
  535.     return(SUCCESS);
  536. #undef tcpHdrPtr
  537. #undef ipHdrPtr
  538. }
  539.  
  540.  
  541. /*
  542.  *----------------------------------------------------------------------
  543.  *
  544.  * TCPRespond --
  545.  *
  546.  *    Send a single message to the TCP at address specified by
  547.  *    the given TCP/IP header.  If flags==0, then we make a copy
  548.  *    of the tcpiphdr at ti and send directly to the addressed host.
  549.  *    This is used to force keep alive messages out using the TCP
  550.  *    template for a connection *tcbPtr->templatePtr.  If flags are given
  551.  *    then we send a message back to the TCP which originated the
  552.  *    segment ti, and discard the mbuf containing it and any other
  553.  *    attached mbufs.
  554.  *
  555.  *    In any case the ack and sequence number of the transmitted
  556.  *    segment are as specified by the parameters.
  557.  *
  558.  * Results:
  559.  *    None.
  560.  *
  561.  * Side effects:
  562.  *    A packet is sent to the remote peer.
  563.  *
  564.  *----------------------------------------------------------------------
  565.  */
  566.  
  567. void
  568. TCPRespond(sockPtr, tcpHdrPtr, ipHdrPtr, ack, seq, flags)
  569.     Sock_InfoPtr    sockPtr;    /* Socket that is sending a response. */
  570.     register Net_TCPHeader *tcpHdrPtr;    /* TCP header from the packet we are
  571.                      * responding to. */
  572.     register Net_IPHeader *ipHdrPtr;    /* IP header from the the packet. */
  573.     TCPSeqNum        ack;        /* Ack and sequence numbers, flags 
  574.                      * to be sent. */
  575.     TCPSeqNum        seq;
  576.     int         flags;
  577. {
  578.     int         window = 0;
  579.     IPS_Packet        packet;
  580.  
  581.     if (sockPtr != (Sock_InfoPtr) NULL) {
  582.     window = Sock_BufSize(sockPtr, SOCK_RECV_BUF, SOCK_BUF_FREE);
  583.     }
  584.  
  585.     IPS_InitPacket(tcpKeepLen, &packet);
  586.  
  587.     if (flags == 0) {
  588.     /*
  589.      * We're sending a response because of a time-out.
  590.      */
  591.     packet.dataLen = tcpKeepLen;
  592.     flags = NET_TCP_ACK_FLAG;
  593.     } else {
  594.     /*
  595.      * We're sending a response back to the origin. Swap the source
  596.      * and destination addresses and ports from the packet.
  597.      */
  598.     packet.dataLen = 0;
  599. #define xchg(a,b,type) { type t; t=a; a=b; b=t; }
  600.     xchg(ipHdrPtr->dest, ipHdrPtr->source, Net_InetAddress);
  601.     xchg(tcpHdrPtr->destPort, tcpHdrPtr->srcPort, unsigned short);
  602. #undef xchg
  603.     }
  604.     packet.hdr.tcpPtr = (Net_TCPHeader *) (packet.data - sizeof(Net_TCPHeader));
  605.     packet.hdrLen = sizeof(Net_TCPHeader);
  606.     packet.ipPtr = (Net_IPHeader *) ((Address)packet.hdr.tcpPtr - 
  607.             sizeof(Net_IPHeader));
  608.  
  609.     *packet.hdr.tcpPtr = *tcpHdrPtr;
  610.     packet.hdr.tcpPtr->seqNum        = Net_HostToNetInt(seq);
  611.     packet.hdr.tcpPtr->ackNum        = Net_HostToNetInt(ack);
  612.     packet.hdr.tcpPtr->dataOffset    = sizeof(Net_TCPHeader) >> 2;
  613.     packet.hdr.tcpPtr->urgentOffset    = 0;
  614.     packet.hdr.tcpPtr->flags        = flags;
  615.     packet.hdr.tcpPtr->window       = Net_HostToNetShort((unsigned short)window);
  616.  
  617.  
  618.     IP_FormatPacket(NET_IP_PROTOCOL_TCP,  timeToLive,
  619.             ipHdrPtr->source, ipHdrPtr->dest, &packet);
  620.  
  621.     if (ips_Debug) {
  622.     (void) fprintf(stderr, 
  623.             "TCP Respond:  <%x,%d,#%d> -> <%x,%d>\n\t", 
  624.             Net_NetToHostInt(ipHdrPtr->source), 
  625.             Net_NetToHostShort(packet.hdr.tcpPtr->srcPort), 
  626.             Net_NetToHostShort(ipHdrPtr->ident),
  627.             Net_NetToHostInt(ipHdrPtr->dest), 
  628.             Net_NetToHostShort(packet.hdr.tcpPtr->destPort));
  629.     TCPPrintHdrFlags(stderr, (unsigned short)flags);
  630.     (void) fprintf(stderr, "  seq=%d, ack=%d, wind=%d\n", 
  631.         Net_NetToHostInt(packet.hdr.tcpPtr->seqNum), 
  632.         Net_NetToHostInt(packet.hdr.tcpPtr->ackNum),
  633.         Net_NetToHostShort(packet.hdr.tcpPtr->window));
  634.     }
  635.     CalcChecksum(&packet, packet.dataLen);
  636.  
  637.  
  638.     (void) IP_Output(&packet, TRUE);
  639.     free(packet.base);
  640. }
  641.  
  642.  
  643. /*
  644.  *----------------------------------------------------------------------
  645.  *
  646.  * CalcChecksum --
  647.  *
  648.  *    Calculates the checksum for the TCP header, pseudo-header and data.
  649.  *    It is assumed that the data immediately follows the TCP header.
  650.  *    The data may include TCP header options.
  651.  *
  652.  * Results:
  653.  *    None.
  654.  *
  655.  * Side effects:
  656.  *    None.
  657.  *
  658.  *----------------------------------------------------------------------
  659.  */
  660.  
  661. static void
  662. CalcChecksum(packetPtr, len)
  663.     IPS_Packet *packetPtr;    /* Packet descriptor. */
  664.     int        len;        /* Length of data following the TCP header. */ 
  665. {
  666.     Net_IPPseudoHdr    pseudoHdr;
  667.     Net_TCPHeader    *tcpPtr = packetPtr->hdr.tcpPtr;
  668.     Net_IPHeader    *ipPtr  = packetPtr->ipPtr;
  669.  
  670.     len += sizeof(Net_TCPHeader);
  671.     pseudoHdr.source    = (ipPtr->source);
  672.     pseudoHdr.dest    = (ipPtr->dest);
  673.     pseudoHdr.zero    = 0;
  674.     pseudoHdr.protocol    = NET_IP_PROTOCOL_TCP;
  675.     pseudoHdr.len    = Net_HostToNetShort(len);
  676.     tcpPtr->checksum = 0;
  677.     tcpPtr->checksum = Net_InetChecksum2(len, (Address) tcpPtr, &pseudoHdr);
  678. }
  679.